package assembly;

import java.awt.Dimension;
import java.util.Scanner;
import simulation.ILoadable;
import simulation.SpringiesConstants;
import util.Vector;


/**
 * Represents a type of spring that has an oscillating rest length
 * 
 * @author Scott Valentine
 * @author Dagbedji Fagnisse
 */
public class Muscle extends Spring {

    /**
     * the default frequency at which the spring oscillates its length
     */
    public static final double DEFAULT_FREQUENCY = Math.PI * 200 * 25;

    /**
     * the default amplitude value for the length oscillation of the spring
     */
    public static final double DEFAULT_AMPLITUE = 100.0;

    private static final String KEYWORD = SpringiesConstants.MUSCLE_KEYWORD;

    // private static Muscle sample;

    private double myAmplitude;
    private double myFrequency;

    // keeps track of the elapsed time since start. (there may be a more elegant
    // way to do this that just keeping track of time)
    private double myTime;

    /**
     * Constructor
     * 
     * @param start mass
     * @param end mass
     * @param length initial rest length
     * @param kVal is the constant of the spring
     * @param amplitude - max value of change of the rest length
     * @param frequency - how quickly is the rest length changing
     */
    public Muscle (Mass start, Mass end, double length, double kVal,
                   double amplitude, double frequency) {
        super(start, end, length, kVal);
        myAmplitude = amplitude;
        myFrequency = DEFAULT_FREQUENCY;
    }

    /**
     * default muscle is created using default values for end masses, springiness, and oscillation
     */
    public Muscle () {
        this(new Mass(Mass.DEFAULT_X, Mass.DEFAULT_Y, Mass.DEFAULT_MASS),
             new Mass(Mass.DEFAULT_X, Mass.DEFAULT_Y, Mass.DEFAULT_MASS), Spring.DEFAULT_LENGTH,
             Spring.DEFAULT_K, DEFAULT_AMPLITUE, DEFAULT_FREQUENCY);
    }

    @Override
    public void update (double elapsedTime, Dimension bounds) {
        double dx = getStart().getX() - getEnd().getX();
        double dy = getStart().getY() - getEnd().getY();

        // update the length of the spring as time elapses
        double len = getLength() + myAmplitude * Math.sin(myTime * myFrequency);

        // force is along spring direction and has magnitude = myK *
        // displacement of spring length
        Vector force =
                new Vector(Vector.angleBetween(dx, dy), getK()
                                                        * (len - Vector.distanceBetween(dx, dy)));

        getStart().applyForce(force);
        force.negate();

        getEnd().applyForce(force);

        // update sprite values based on attached masses
        setCenter(getCenter(getStart(), getEnd()));
        setSize(getSize(getStart(), getEnd()));
        setVelocity(Vector.angleBetween(dx, dy), 0);

        myTime += elapsedTime;

    }

    @Override
    public ILoadable load(Scanner line, Object o) {
        Mass m1 = ((Assembly) o).getMasses().get(line.nextInt());
        Mass m2 = ((Assembly) o).getMasses().get(line.nextInt());
        double restLength = line.nextDouble();
        double ks = line.nextDouble();
        double amplitude = line.nextDouble();
        return new Muscle(m1, m2, restLength, ks, amplitude, DEFAULT_FREQUENCY);
    }
    
    @Override
    public String getKeyword () {
        return KEYWORD;
    }
}
